home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
news
/
inn1.000
/
inn1.4sec-linux-src.tar
/
inn
/
innd
/
his.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-29
|
6KB
|
280 lines
/* $Revision: 1.21 $
**
** History file routines.
*/
#include "innd.h"
#include "dbz.h"
STATIC char HIShistpath[] = _PATH_HISTORY;
STATIC FILE *HISwritefp;
STATIC int HISreadfd;
STATIC int HISdirty;
STATIC int HISincore = INND_DBZINCORE;
/*
** Set up the history files.
*/
void
HISsetup()
{
if (HISwritefp == NULL) {
/* Open the history file for appending formatted I/O. */
if ((HISwritefp = fopen(HIShistpath, "a")) == NULL) {
syslog(L_FATAL, "%s cant fopen %s %m", LogName, HIShistpath);
exit(1);
}
CloseOnExec((int)fileno(HISwritefp), TRUE);
/* Open the history file for reading. */
if ((HISreadfd = open(HIShistpath, O_RDONLY)) < 0) {
syslog(L_FATAL, "%s cant open %s %m", LogName, HIShistpath);
exit(1);
}
CloseOnExec(HISreadfd, TRUE);
/* Open the DBZ file. */
(void)dbzincore(HISincore);
(void)dbzwritethrough(1);
if (dbminit(HIShistpath) < 0) {
syslog(L_FATAL, "%s cant dbminit %s %m", HIShistpath, LogName);
exit(1);
}
}
}
/*
** Synchronize the in-core history file (flush it).
*/
void
HISsync()
{
if (HISdirty) {
if (dbzsync()) {
syslog(L_FATAL, "%s cant dbzsync %m", LogName);
exit(1);
}
HISdirty = 0;
}
}
/*
** Close the history files.
*/
void
HISclose()
{
if (HISwritefp != NULL) {
/* Since dbmclose calls dbzsync we could replace this line with
* "HISdirty = 0;". Oh well, it keeps the abstraction clean. */
HISsync();
if (dbmclose() < 0)
syslog(L_ERROR, "%s cant dbmclose %m", LogName);
if (fclose(HISwritefp) == EOF)
syslog(L_ERROR, "%s cant fclose history %m", LogName);
HISwritefp = NULL;
if (close(HISreadfd) < 0)
syslog(L_ERROR, "%s cant close history %m", LogName);
HISreadfd = -1;
}
}
/*
** File in the DBZ datum for a Message-ID, making sure not to copy any
** illegal characters.
*/
STATIC void
HISsetkey(p, keyp)
register char *p;
datum *keyp;
{
static BUFFER MessageID;
register char *dest;
register int i;
/* Get space to hold the ID. */
i = strlen(p);
if (MessageID.Data == NULL) {
MessageID.Data = NEW(char, i + 1);
MessageID.Size = i;
}
else if (MessageID.Size < i) {
RENEW(MessageID.Data, char, i + 1);
MessageID.Size = i;
}
for (keyp->dptr = dest = MessageID.Data; *p; p++)
if (*p == HIS_FIELDSEP || *p == '\n')
*dest++ = HIS_BADCHAR;
else
*dest++ = *p;
*dest = '\0';
keyp->dsize = dest - MessageID.Data + 1;
}
/*
** Get the list of files under which a Message-ID is stored.
*/
char *
HISfilesfor(MessageID)
char *MessageID;
{
static BUFFER Files;
char *dest;
datum key;
datum val;
long offset;
register char *p;
register int i;
/* Get the seek value into the history file. */
HISsetkey(MessageID, &key);
val = dbzfetch(key);
if (val.dptr == NULL || val.dsize != sizeof offset)
return NULL;
/* Get space. */
if (Files.Data == NULL) {
Files.Size = BUFSIZ;
Files.Data = NEW(char, Files.Size);
}
/* Copy the value to an aligned spot. */
for (p = val.dptr, dest = (char *)&offset, i = sizeof offset; --i >= 0; )
*dest++ = *p++;
if (lseek(HISreadfd, offset, SEEK_SET) == -1)
return NULL;
/* Read the text until \n or EOF. */
for (Files.Used = 0; ; ) {
i = read(HISreadfd,
&Files.Data[Files.Used], Files.Size - Files.Used - 1);
if (i <= 0)
return NULL;
Files.Used += i;
Files.Data[Files.Used] = '\0';
if ((p = strchr(Files.Data, '\n')) != NULL) {
*p = '\0';
break;
}
/* If we have half our buffer left, get more space. */
if (Files.Size - Files.Used < Files.Size / 2) {
Files.Size += BUFSIZ;
RENEW(Files.Data, char, Files.Size);
}
}
/* Move past the first two fields -- Message-ID and date info. */
if ((p = strchr(Files.Data, HIS_FIELDSEP)) == NULL)
return NULL;
if ((p = strchr(p + 1, HIS_FIELDSEP)) == NULL)
return NULL;
/* Translate newsgroup separators to slashes, return the fieldstart. */
for (dest = ++p; *p; p++)
if (*p == '.')
*p = '/';
return dest;
}
/*
** Have we already seen an article?
*/
BOOL
HIShavearticle(MessageID)
char *MessageID;
{
datum key;
datum val;
HISsetkey(MessageID, &key);
val = dbzfetch(key);
return val.dptr != NULL;
}
/*
** Turn a history filename entry from slashes to dots. It's a pity
** we have to do this.
*/
STATIC void
HISslashify(p)
register char *p;
{
register char *last;
for (last = NULL; *p; p++) {
if (*p == '/') {
*p = '.';
last = p;
}
else if (*p == ' ' && last != NULL)
*last = '/';
}
if (last)
*last = '/';
}
/*
** Write a history entry.
*/
BOOL
HISwrite(Data, paths)
ARTDATA *Data;
char *paths;
{
static char NOPATHS[] = "";
long offset;
datum key;
datum val;
int i;
HISsetkey(Data->MessageID, &key);
if (paths != NULL && paths[0] != '\0')
HISslashify(paths);
else
paths = NOPATHS;
offset = ftell(HISwritefp);
if (Data->Expires > 0)
i = fprintf(HISwritefp, "%s%c%ld%c%ld%c%ld%c%s\n",
key.dptr, HIS_FIELDSEP,
(long)Data->Arrived, HIS_SUBFIELDSEP, (long)Data->Expires,
HIS_SUBFIELDSEP, (long)Data->Posted, HIS_FIELDSEP,
paths);
else
i = fprintf(HISwritefp, "%s%c%ld%c%s%c%ld%c%s\n",
key.dptr, HIS_FIELDSEP,
(long)Data->Arrived, HIS_SUBFIELDSEP, HIS_NOEXP,
HIS_SUBFIELDSEP, (long)Data->Posted, HIS_FIELDSEP,
paths);
if (i == EOF || fflush(HISwritefp) == EOF) {
/* The history line is now an orphan... */
IOError("history");
syslog(L_ERROR, "%s cant write history %m", LogName);
return FALSE;
}
/* Set up the database values and write them. */
val.dptr = (char *)&offset;
val.dsize = sizeof offset;
if (dbzstore(key, val) < 0) {
IOError("history database");
syslog(L_ERROR, "%s cant dbzstore %m", LogName);
return FALSE;
}
if (++HISdirty >= ICD_SYNC_COUNT)
HISsync();
return TRUE;
}